﻿using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tool.Configs;
using Tool.Model;

namespace Tool.Helper.Dm
{
    public class DmHelperEx
    {
        private static DmHelper _dm;
        private static bool _lock = false;
        private int _handler;
        private Random _rand = new Random();

        public int Handler { get { return _handler; } set { _handler = value; } }
        public DmHelper Dm { get { return _dm; } }

        public bool Init()
        {
            lock (this)
            {
                if (!_lock)
                {
                    var result = RegisterHelper.RegisteExcelDll();
                    if (result)
                    {
                        if (_dm == null)
                        {
                            try
                            {
                                _dm = new DmHelper();
                                _dm.SetPathEx();
                                _lock = true;
                            }
                            catch (Exception ex)
                            {
                                LogHelper.LogError(ex);
                                return false;
                            }
                        }
                    }
                    else { LogHelper.LogError("加载 dm.dll 失败"); }
                    return result;
                }
                return true;
            }
        }

        #region //颜色

        /// <summary>
        /// 查找单色
        /// </summary>
        /// <param name="x1">区域的左上X坐标</param>
        /// <param name="y1">区域的左上Y坐标</param>
        /// <param name="x2">区域的右下X坐标</param>
        /// <param name="y2">区域的右下Y坐标</param>
        /// <param name="color">颜色 格式为"RRGGBB-DRDGDB",</param>
        /// <param name="sim">相似度,取值范围0.1-1.0</param>
        /// <param name="dir">查找方向 0: 从左到右,从上到下 1: 从左到右,从下到上  2: 从右到左,从上到下   3: 从右到左,从下到上   4：从中心往外查找  5: 从上到下,从左到右    6: 从上到下,从右到左  7: 从下到上,从左到右  8: 从下到上,从右到左</param>
        /// <returns>查找到返回坐标，否则返回-1</returns>
        public FindResultEntity FindColor(int x1, int y1, int x2, int y2, string color, double sim, int dir)
        {
            FindResultEntity result = new FindResultEntity();
            int x, y;
            var res = _dm.FindColor(x1, y1, x2, y2, color, sim, dir, out x, out y);
            if (res == 1)
            {
                result.PointInfo = new Point(x, y);
            }
            return result;
        }

        /// <summary>
        /// 查找多色
        /// </summary>
        /// <param name="x1">区域的左上X坐标</param>
        /// <param name="y1">区域的左上Y坐标</param>
        /// <param name="x2">区域的右下X坐标</param>
        /// <param name="y2">区域的右下Y坐标</param>
        /// <param name="first_color">颜色 格式为"RRGGBB-DRDGDB",</param>
        /// <param name="offset_color">偏移颜色 可以支持任意多个点</param>
        /// <param name="sim">相似度,取值范围0.1-1.0</param>
        /// <param name="dir">查找方向 0: 从左到右,从上到下 1: 从左到右,从下到上  2: 从右到左,从上到下   3: 从右到左,从下到上   4：从中心往外查找  5: 从上到下,从左到右    6: 从上到下,从右到左  7: 从下到上,从左到右  8: 从下到上,从右到左</param>
        /// <returns>返回找到的firstColor颜色的坐标</returns>
        public FindResultEntity FindMultiColor(int x1, int y1, int x2, int y2, string firstColor, string offsetColor, double sim, int dir)
        {
            FindResultEntity result = new FindResultEntity();
            int x, y;
            var data = _dm.FindMultiColor(x1, y1, x2, y2, firstColor, offsetColor, sim, dir, out x, out y);
            result.PointInfo = new Point(x, y);
            if (data == 1)
            {
                result.Result = true;
            }
            return result;
        }

        /// <summary>
        /// 查找多色
        /// </summary>
        /// <param name="x1">区域的左上X坐标</param>
        /// <param name="y1">区域的左上Y坐标</param>
        /// <param name="x2">区域的右下X坐标</param>
        /// <param name="y2">区域的右下Y坐标</param>
        /// <param name="first_color">颜色 格式为"RRGGBB-DRDGDB",</param>
        /// <param name="offset_color">偏移颜色 可以支持任意多个点</param>
        /// <param name="sim">相似度,取值范围0.1-1.0</param>
        /// <param name="dir">查找方向 0: 从左到右,从上到下 1: 从左到右,从下到上  2: 从右到左,从上到下   3: 从右到左,从下到上   4：从中心往外查找  5: 从上到下,从左到右    6: 从上到下,从右到左  7: 从下到上,从左到右  8: 从下到上,从右到左</param>
        /// <returns>返回找到的第一个颜色的坐标</returns>
        public FindResultEntity FindMultiColorE(int x1, int y1, int x2, int y2, string firstColor, string offsetColor, double sim, int dir)
        {
            FindResultEntity result = new FindResultEntity();
            string str = _dm.FindMultiColorE(x1, y1, x2, y2, firstColor, offsetColor, sim, dir);
            if (!string.IsNullOrEmpty(str))
            {

                var arr = str.Split('|');
                result.PointInfo = new Point(Convert.ToInt32(arr[0]), Convert.ToInt32(arr[1]));
                if (result.PointInfo.X >= 0 && result.PointInfo.Y >= 0)
                {
                    result.Result = true;
                }
            }
            return result;
        }

        /// <summary>
        /// 查找多色
        /// </summary>
        /// <param name="x1">区域的左上X坐标</param>
        /// <param name="y1">区域的左上Y坐标</param>
        /// <param name="x2">区域的右下X坐标</param>
        /// <param name="y2">区域的右下Y坐标</param>
        /// <param name="first_color">颜色 格式为"RRGGBB-DRDGDB",</param>
        /// <param name="offset_color">偏移颜色 可以支持任意多个点</param>
        /// <param name="sim">相似度,取值范围0.1-1.0</param>
        /// <param name="dir">查找方向 0: 从左到右,从上到下 1: 从左到右,从下到上  2: 从右到左,从上到下   3: 从右到左,从下到上   4：从中心往外查找  5: 从上到下,从左到右    6: 从上到下,从右到左  7: 从下到上,从左到右  8: 从下到上,从右到左</param>
        /// <returns>返回所有颜色信息的坐标值</returns>
        public FindResultListEntity FindMultiColorEx(int x1, int y1, int x2, int y2, string firstColor, string offsetColor, double sim, int dir)
        {
            FindResultListEntity result = new FindResultListEntity();
            string str = _dm.FindMultiColorEx(x1, y1, x2, y2, firstColor, offsetColor, sim, dir);
            var count = _dm.GetResultCount(str);
            int intX, intY;
            for (int i = 0; i < count; i++)
            {
                var a = _dm.GetResultPos(str, i, out intX, out intY);
                if (a == 1)
                {
                    result.PointRs.Add(new Point { X = intX, Y = intY });
                }
            }
            return result;
        }

        #endregion

        #region  //图片

        /// <summary>
        /// 查找指定区域内的图片,位图必须是24位色格式,支持透明色,当图像上下左右4个顶点的颜色一样时,则这个颜色将作为透明色处理.可以查找多个图片,只返回第一个找到的X Y坐标.
        /// </summary>
        /// <param name="x1">区域的左上X坐标</param>
        /// <param name="y1">区域的左上Y坐标</param>
        /// <param name="x2">区域的右下X坐标</param>
        /// <param name="y2">区域的右下Y坐标</param>
        /// <param name="picName">图片名,可以是多个图片,比如"test.bmp|test2.bmp|test3.bmp"</param>
        /// <param name="deltaColor">颜色色偏 比如"203040" 表示RGB的色偏分别是20 30 40 (这里是16进制表示)</param>
        /// <param name="sim">相似度,取值范围0.1-1.0</param>
        /// <param name="dir">查找方向 0: 从左到右,从上到下 1: 从左到右,从下到上 2: 从右到左,从上到下 3: 从右到左, 从下到上</param>
        /// <returns></returns>
        public FindResultEntity FindPic(int x1, int y1, int x2, int y2, string picName, string deltaColor, double sim, int dir)
        {
            FindResultEntity result = new FindResultEntity();
            int intX, intY;
            var aa = _dm.FindPic(x1, y1, x2, y2, picName, deltaColor, sim, dir, out intX, out intY);
            if (aa == 1)
            {
                result.PointInfo = new Point(intX, intY);
                result.Result = true;
            }
            return result;
        }

        /// <summary>
        /// 查找指定区域内的图片,位图必须是24位色格式,支持透明色,当图像上下左右4个顶点的颜色一样时,则这个颜色将作为透明色处理.可以查找多个图片,只返回第一个找到的X Y坐标.
        /// </summary>
        /// <param name="x1">区域的左上X坐标</param>
        /// <param name="y1">区域的左上Y坐标</param>
        /// <param name="x2">区域的右下X坐标</param>
        /// <param name="y2">区域的右下Y坐标</param>
        /// <param name="picName">图片名,可以是多个图片,比如"test.bmp|test2.bmp|test3.bmp"</param>
        /// <param name="deltaColor">颜色色偏 比如"203040" 表示RGB的色偏分别是20 30 40 (这里是16进制表示)</param>
        /// <param name="sim">相似度,取值范围0.1-1.0</param>
        /// <param name="dir">查找方向 0: 从左到右,从上到下 1: 从左到右,从下到上 2: 从右到左,从上到下 3: 从右到左, 从下到上</param>
        /// <returns></returns>
        public FindResultEntity FindPicE(int x1, int y1, int x2, int y2, string picName, string deltaColor, double sim, int dir)
        {
            FindResultEntity result = new FindResultEntity();
            var aa = _dm.FindPicE(x1, y1, x2, y2, picName, deltaColor, sim, dir);
            if (string.IsNullOrEmpty(aa))
            {
                var pos = aa.Split('|');
                result.Index = Convert.ToInt32(pos[0]);
                result.PointInfo = new Point(Convert.ToInt32(pos[1]), Convert.ToInt32(pos[2]));
                result.Result = true;
            }
            return result;
        }
        /// <summary>
        /// 获取(x,y)的颜色,颜色返回格式"RRGGBB"
        /// </summary>
        /// <param name="x">X坐标</param>
        /// <param name="y">Y坐标</param>
        /// <returns></returns>
        public string GetColor(int x, int y)
        {
            return _dm.GetColor(x, y);
        }
        #endregion

        #region  //窗口

        /// <summary>
        /// 设置全局路径,设置了此路径后,所有接口调用中,相关的文件都相对于此路径. 比如图片,字库等.路径为配置文件中的路径
        /// </summary>
        /// <returns></returns>
        public bool SetPath(string path = "")
        {
            return _dm.SetPathEx(path);
        }


        /// <summary>
        /// 获取窗口句柄
        /// </summary>
        /// <param name="winName">窗口</param>
        /// <returns>成功返回大于0的句柄</returns>
        public int EnumWindow(string winName)
        {
            int result = -1;
            var hand = _dm.EnumWindow(0, winName, "", 1 + 4 + 8 + 16);
            if (!string.IsNullOrEmpty(hand))
            {
                Int32.TryParse(hand, out result);
                _handler = result;
            }
            return result;
        }
        /// <summary>
        /// 查找符合类名或者标题名的顶层可见窗口
        /// </summary>
        /// <param name="className">窗口类名，如果为空，则匹配所有. 这里的匹配是模糊匹配.</param>
        /// <param name="winName">窗口标题,如果为空，则匹配所有.这里的匹配是模糊匹配.</param>
        /// <returns></returns>
        public int FindWindow(string winName, string className = "")
        {
            return _handler = Dm.FindWindow(className, winName);
        }


        /// <summary>
        /// 绑定窗口
        /// </summary>
        /// <param name="handler">句柄</param>
        /// <returns></returns>
        public bool BindWindow(int handler)
        {
            var a = _dm.BindWindow(handler, "normal", "normal", "windows", 0);
            return a == 1 ? true : false;
        }

        /// <summary>
        /// 解绑窗口
        /// </summary>
        /// <returns></returns>
        public bool UnBindWindow()
        {
            return _dm.UnBindWindow() == 1 ? true : false;
        }

        /// <summary>
        /// 获取窗口客户区域在屏幕上的位置
        /// </summary>
        /// <param name="handler">句柄</param>
        /// <returns></returns>
        public LocationEntity GetClientRect(int? handler = null)
        {
            LocationEntity result = new LocationEntity();
            if (handler != null)
            {
                int x1, y1, x2, y2;
                var aa = _dm.GetClientRect(Convert.ToInt32(handler), out x1, out y1, out x2, out y2);
                if (aa == 1)
                {
                    result.LocationL = new Point(x1, y1);
                    result.LocationR = new Point(x2, y2);
                    result.Result = true;
                }
            }
            else
            {
                if (_handler > 0)
                {
                    int x1, y1, x2, y2;
                    var aa = _dm.GetClientRect(_handler, out x1, out y1, out x2, out y2);
                    if (aa == 1)
                    {
                        result.LocationL = new Point(x1, y1);
                        result.LocationR = new Point(x2, y2);
                        result.Result = true;
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 获取窗口在屏幕上的位置
        /// </summary>
        /// <param name="handler"></param>
        /// <returns></returns>
        public LocationEntity GetWindowRect(int? handler = null)
        {
            LocationEntity result = new LocationEntity();
            if (handler != null)
            {
                int x1, y1, x2, y2;
                var aa = _dm.GetWindowRect(Convert.ToInt32(handler), out x1, out y1, out x2, out y2);
                if (aa == 1)
                {
                    result.LocationL = new Point(x1, y1);
                    result.LocationR = new Point(x2, y2);
                    result.Result = true;
                }
            }
            else
            {
                if (_handler > 0)
                {
                    int x1, y1, x2, y2;
                    var aa = _dm.GetWindowRect(_handler, out x1, out y1, out x2, out y2);
                    if (aa == 1)
                    {
                        result.LocationL = new Point(x1, y1);
                        result.LocationR = new Point(x2, y2);
                        result.Result = true;
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 移动指定窗口到指定位置
        /// </summary>
        /// <param name="handler"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public bool MoveWindow(int x, int y, int? handler = null)
        {
            if (handler != null)
            {
                return _dm.MoveWindow(Convert.ToInt32(handler), x, y) == 1 ? true : false;
            }
            else
            {
                if (_handler > 0)
                {
                    return _dm.MoveWindow(_handler, x, y) == 1 ? true : false;
                }
                return false;
            }
        }

        /// <summary>
        /// 获取窗口客户区域的宽度和高度
        /// </summary>
        /// <param name="handler"></param>
        /// <returns></returns>
        public SizeEntity GetClientSize(int? handler = null)
        {
            SizeEntity result = new SizeEntity();
            if (handler != null)
            {
                int w, h;
                var aa = _dm.GetClientSize(Convert.ToInt32(handler), out w, out h);
                if (aa == 1)
                {
                    result.Width = w;
                    result.Height = h;
                    result.Result = true;
                }
            }
            else if (_handler > 0)
            {
                int w, h;
                var aa = _dm.GetClientSize(_handler, out w, out h);
                if (aa == 1)
                {
                    result.Width = w;
                    result.Height = h;
                    result.Result = true;
                }
            }
            return result;
        }

        /// <summary>
        /// 设置窗口客户区域的宽度和高度
        /// </summary>
        /// <param name="handler">句柄</param>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        /// <returns></returns>
        public bool SetClientSize(int width, int height, int? handler = null)
        {
            int result = 0;
            if (handler != null)
            {
                result = _dm.SetClientSize(Convert.ToInt32(handler), width, height);
            }
            else if (_handler > 0)
            {
                result = _dm.SetClientSize(_handler, width, height);
            }
            return result != 0;
        }


        /// <summary>
        /// 获取屏幕的高度
        /// </summary>
        /// <returns></returns>
        public long GetScreenHeight()
        {
            return _dm.GetScreenHeight();
        }

        /// <summary>
        /// 获取屏幕的宽度
        /// </summary>
        /// <returns></returns>
        public long GetScreenWidth()
        {
            return _dm.GetScreenWidth();
        }

        /// <summary>
        /// 设置窗口的大小
        /// </summary>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        /// <param name="handler">指定的窗口句柄</param>
        /// <returns></returns>
        public bool SetWindowSize(int width, int height, int? handler = null)
        {
            int result = 0;
            if (handler != null)
            {
                result = _dm.SetWindowSize(Convert.ToInt32(handler), width, height);
            }
            else if (_handler > 0)
            {
                result = _dm.SetWindowSize(_handler, width, height);
            }
            return result != 0;
        }

        /// <summary>
        /// 获取窗口的大小
        /// </summary>
        /// <param name="handler"></param>
        /// <returns></returns>
        public SizeEntity GetWindowSize(int? handler = null)
        {
            SizeEntity data = new SizeEntity();
            var result = GetWindowRect(handler);
            if (!result.Result)
            {
                return data;
            }
            data.Result = true;
            data.Width = result.LocationR.X - result.LocationL.X;
            data.Height = result.LocationR.Y - result.LocationL.Y;
            return data;
        }

        #endregion

        #region  //鼠标

        /// <summary>
        /// 获取鼠标位置
        /// </summary>
        /// <returns></returns>
        public FindResultEntity GetCursorPos()
        {
            FindResultEntity result = new FindResultEntity();
            int x, y;
            var aa = _dm.GetCursorPos(out x, out y);
            if (aa == 1)
            {
                result.PointInfo = new Point(x, y);
                result.Result = true;
            }
            return result;
        }

        /// <summary>
        /// 移动鼠标
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public bool MoveTo(int x, int y)
        {
            return _dm.MoveTo(x, y) == 1 ? true : false;
        }
        /// <summary>
        /// 移动鼠标
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public bool MoveTo(Point point)
        {
            return MoveTo(point.X, point.Y);
        }
        /// <summary>
        /// 移动鼠标到目的范围内的任意一点
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="w"></param>
        /// <param name="h"></param>
        /// <returns></returns>
        public FindResultEntity MoveTo(int x, int y, int w, int h)
        {
            FindResultEntity result = new FindResultEntity();
            var str = _dm.MoveToEx(x, y, w, h);
            if (string.IsNullOrEmpty(str))
            {
                var arr = str.Split('|');
                result.PointInfo = new Point(Convert.ToInt32(arr[0]), Convert.ToInt32(arr[1]));
                result.Result = true;
            }
            return result;
        }

        #region  //基本点击
        public bool LeftClick()
        {
            return _dm.LeftClick() == 1 ? true : false;
        }
        public bool LeftDoubleClick()
        {
            return _dm.LeftDoubleClick() == 1 ? true : false;
        }
        public bool LeftDown()
        {
            return _dm.LeftDown() == 1 ? true : false;
        }
        public bool LeftUp()
        {
            return _dm.LeftUp() == 1 ? true : false;
        }
        public bool MiddleClick()
        {
            return _dm.MiddleClick() == 1 ? true : false;
        }
        public bool MiddleDown()
        {
            return _dm.MiddleDown() == 1 ? true : false;
        }
        public bool MiddleUp()
        {
            return _dm.MiddleUp() == 1 ? true : false;
        }
        public bool RightClick()
        {
            return _dm.RightClick() == 1 ? true : false;
        }
        public bool RightDown()
        {
            return _dm.RightDown() == 1 ? true : false;
        }
        public bool RightUp()
        {
            return _dm.RightUp() == 1 ? true : false;
        }
        public bool WheelUp()
        {
            return _dm.WheelUp() == 1 ? true : false;
        }
        public bool WheelDown()
        {
            return _dm.WheelDown() == 1 ? true : false;
        }
        #endregion

        /// <summary>
        /// 移动鼠标
        /// </summary>
        /// <param name="point">坐标</param>
        /// <returns></returns>
        public bool MoveTrack(Point point)
        {
            return MoveTrack(point.X, point.Y);
        }
        /// <summary>
        /// 移动鼠标
        /// </summary>
        /// <param name="targetX"></param>
        /// <param name="targetY"></param>
        /// <returns></returns>
        public bool MoveTrack(int targetX, int targetY)
        {
            int currentX, currentY, distanceX, distanceY, distanceTwoPoint, moveX = 1, moveY = 1, rndNumber, moveCount, moveStepX = 1, moveStepY = 1, positionX = 1, positionY = 1;
            int maxValue, minValue, order, numValue = 0;
            order = _rand.Next(0, 1);
            maxValue = _rand.Next(20, 60);
            minValue = _rand.Next(-60, -20);
            while (true)
            {
                var point = GetCursorPos();
                if (!point.Result)
                {
                    return false;
                }
                currentX = point.PointInfo.X;
                currentY = point.PointInfo.Y;
                distanceX = Math.Abs(currentX - targetX); //x边长
                distanceY = Math.Abs(currentY - targetY); //y边长
                distanceTwoPoint = Convert.ToInt32(Math.Sqrt(distanceX * distanceX + distanceY * distanceY));//斜边边长
                while (true)
                {
                    rndNumber = _rand.Next(24, 30);
                    moveCount = distanceTwoPoint / rndNumber;
                    if (moveCount > 0)
                    {
                        moveStepX = distanceX / moveCount;
                        moveStepY = distanceY / moveCount;
                        break;
                    }
                    else
                    {
                        MoveTo(targetX, targetY);
                        //   Console.WriteLine("moveX:" + targetX + "; moveY:" + targetX + "  num:" + aa++);
                        return true;
                    }
                }
                positionX = targetX - currentX;
                if (positionX >= 0)
                {
                    positionX = 1;
                }
                else
                {
                    positionX = -1;
                }
                positionY = targetY - currentY;
                if (positionY >= 0)
                {
                    positionY = 1;
                }
                else
                {
                    positionY = -1;
                }
                if (order == 0)
                {
                    numValue = numValue + 2;
                    if (numValue >= maxValue)
                    {
                        maxValue = _rand.Next(20, 60);
                        minValue = _rand.Next(-60, -20);
                        numValue = 0;
                        order = 1;
                        moveY = currentY + moveStepY * positionY;
                        moveX = currentX + moveStepX * positionX;
                    }
                    else
                    {
                        moveY = currentY + moveStepY * positionY + 2;
                        moveX = currentX + moveStepX * positionX + 2;
                    }
                }
                else
                {
                    numValue = numValue - 2;
                    if (numValue <= minValue)
                    {
                        maxValue = _rand.Next(20, 60);
                        minValue = _rand.Next(-60, -20);
                        numValue = 0;
                        order = 0;
                        moveY = currentY + moveStepY * positionY;
                        moveX = currentX + moveStepX * positionX;
                    }
                    else
                    {
                        moveY = currentY + moveStepY * positionY - 2;
                        moveX = currentX + moveStepX * positionX - 2;
                    }
                }
                MoveTo(moveX, moveY);
                //  Console.WriteLine("moveX:" + moveX + "; moveY:" + moveY+"  num:"+aa++);
                if (Math.Abs(moveX - targetX) < _rand.Next(100, 120) || Math.Abs(moveY - targetY) < _rand.Next(100, 120))
                {
                    Thread.Sleep(_rand.Next(2, 3));
                }
                else
                {
                    Thread.Sleep(1);
                }
                if (Math.Abs(moveX - targetX) < 2 && Math.Abs(moveY - targetY) < 2)
                {
                    MoveTo(targetX, targetY);
                    return true;
                }
            }
        }
       
        public bool MoveTrackEx(int targetX,int targetY)
        {
            // 获取当前鼠标位置（伪代码）
            var current = GetCursorPos();
            if (!current.Result)
            {
                return false;
            }
            int x = current.PointInfo.X;
            int y = current.PointInfo.Y;
            // 计算主轴距离（取 x 或 y 方向的最大绝对差值作为步数基准）
            int cs = Math.Abs(x - targetX) > Math.Abs(y - targetY) ? Math.Abs(x - targetX) : Math.Abs(y - targetY);
            if (cs == 0) // 已在目标点
            {
                return false;
            }

            // 计算每步的单位方向增量（浮点，保留精度）
            double stepX = (double)(targetX - x) / cs;
            double stepY = (double)(targetY - y) / cs;
            // 初始随机参数
            int moveStep = (int)(23 * _rand.NextDouble()) + 21;       // 步长：21~43
            int offsetX = (int)(6 * _rand.NextDouble());             // X 偏差：0~5
            int offsetY = (int)(4 * _rand.NextDouble());             // Y 偏差：0~3
            int randomCounter = 0;
            int delayMs = (int)(3 * _rand.NextDouble()) +3;         // 延迟：6~10ms

            // 主循环：直到接近目标点
            while (x != targetX || y != targetY)
            {
                // 按当前步长推进
                x += (int)Math.Round(stepX * moveStep);
                y += (int)Math.Round(stepY * moveStep);
                randomCounter++;

                // 每 4 步重新生成随机扰动
                if (randomCounter == 4)
                {
                    offsetX = (int)(6 * _rand.NextDouble());
                    offsetY = (int)(4 * _rand.NextDouble());
                    moveStep = (int)(23 * _rand.NextDouble()) + 21;
                    randomCounter = 0;
                }
                // 移动到带偏差的位置（伪代码）

                 MoveTo(x + offsetX, y + offsetY);
                // 延迟（伪代码：实际可用 Thread.Sleep）
                Thread.Sleep(delayMs);
                // 检查是否已足够接近终点
                if (Math.Abs(x - targetX) <= moveStep && Math.Abs(y - targetY) <= moveStep)
                {
                    x = targetX;
                    y = targetY;
                    // 最终精确移动到目标点（伪代码）
                     MoveTo(targetX, targetY);
                    break;
                }
            }
            return true;
        }

      
        /// <summary>
        /// 从 (x1, y1) 平滑拖动鼠标到 (x2, y2)
        /// </summary>
        /// <param name="x1"></param>
        /// <param name="y1"></param>
        /// <param name="x2"></param>
        /// <param name="y2"></param>
        public void DragMouseFromTo(int x1, int y1, int x2, int y2)
        {
            // 应用初始随机扰动 + 全局偏移（模拟人类不精准点击）
            int startX = x1 + (int)(20 * _rand.NextDouble()) + 20;
            int startY = y1 + (int)(20 * _rand.NextDouble()) + 20 ;
            int endX = x2 + (int)(20 * _rand.NextDouble()) + 20;
            int endY = y2 + (int)(20 * _rand.NextDouble()) + 20 ;

            // 移动到起始位置（可选：有些场景直接从当前位置开始拖）
             MoveTo(startX, startY);  // 伪代码
            // 按下左键
            LeftDown();
            // 计算总距离和步数
            int totalSteps = Math.Max(Math.Abs(endX - startX), Math.Abs(endY - startY));
            totalSteps = Math.Max(totalSteps, 10); // 至少 10 步保证平滑
            for (int i = 0; i <= totalSteps; i++)
            {
                double t = (double)i / totalSteps; // 插值比例 [0, 1]
                int currentX = (int)Math.Round(startX + t * (endX - startX));
                int currentY = (int)Math.Round(startY + t * (endY - startY));
                // 移动到当前插值点
                 MoveTo(currentX, currentY);  // 伪代码
                // 可加入微小随机延迟模拟人类操作
                Thread.Sleep(5 + _rand.Next(4)); // 5~8m
            }
            // 释放左键
             LeftUp(); 
        }

        #endregion

        #region   //键盘
        public bool KeyDown(int keyAsicc)
        {
            return _dm.KeyDown(keyAsicc) == 1 ? true : false;
        }
        public bool KeyUp(int keyAsicc)
        {
            return _dm.KeyUp(keyAsicc) == 1 ? true : false;
        }
        public bool KeyPress(int keyAsicc)
        {
            return _dm.KeyPress(keyAsicc) == 1 ? true : false;
        }
        public bool KeyDownChar(string keyStr)
        {
            return _dm.KeyDownChar(keyStr) == 1 ? true : false;
        }
        #endregion

        #region  //常用封装方法

        /// <summary>
        /// 添加日志事件委托
        /// </summary>
        /// <param name="str"></param>
        public delegate void AddLogEventHandler(string str);
        public event AddLogEventHandler AddLogEvent;
     
        /// <summary>
        /// 多点找色是否存在
        /// </summary>
        /// <param name="x1">区域的左上X坐标</param>
        /// <param name="y1">区域的左上Y坐标</param>
        /// <param name="x2">区域的右下X坐标</param>
        /// <param name="y2">区域的右下Y坐标</param>
        /// <param name="first_color">颜色 格式为"RRGGBB-DRDGDB",</param>
        /// <param name="offset_color">偏移颜色 可以支持任意多个点</param>
        /// <param name="sim">相似度,取值范围0.1-1.0</param>
        /// <param name="log">输出日志，当找到时输出</param>
        /// <returns>返回查找结果及查找的坐标</returns>
        public FindResultEntity FindColorExist(int x1, int y1, int x2, int y2, string colorFirst, string colorOffset, double sim, string log)
        {
            var result = FindMultiColor(x1, y1, x2, y2, colorFirst, colorOffset, sim, 0);
            if (result.Result && !string.IsNullOrEmpty(log))
            {
                AddLogEvent(log + " " + result.PointInfo.X + "," + result.PointInfo.Y);
            }
            return result;
        }

        /// <summary>
        /// 多点找色，然后单击
        /// </summary>
        /// <param name="x1">区域的左上X坐标</param>
        /// <param name="y1">区域的左上Y坐标</param>
        /// <param name="x2">区域的右下X坐标</param>
        /// <param name="y2">区域的右下Y坐标</param>
        /// <param name="first_color">颜色 格式为"RRGGBB-DRDGDB",</param>
        /// <param name="offset_color">偏移颜色 可以支持任意多个点</param>
        /// <param name="preDelay">移动前延时</param>
        /// <param name="postDelay">点击后延时</param>
        /// <param name="sim">相似度,取值范围0.1-1.0</param>
        /// <param name="isTrack">是否轨迹移动</param>
        /// <param name="log">输出日志，当找到时输出</param>
        /// <param name="clickDelay">移动后单击前延时，默认100-200范围内</param>
        /// <returns>返回查找结果及查找的坐标</returns>
        public FindResultEntity FindColorClick(int x1, int y1, int x2, int y2, string colorFirst, string colorOffset, int preDelay, int postDelay, double sim, bool isTrack, string log, int floatX, int floatY, int clickDelay = 200)
        {
            var result = FindColorExist(x1, y1, x2, y2, colorFirst, colorOffset, sim, log);
            if (result.Result)
            {
                MoveClick(result.PointInfo.X, result.PointInfo.Y, preDelay, postDelay, isTrack, floatX, floatY, clickDelay);
            }
            return result;
        }
        /// <summary>
        ///  多点找色，然后在指定区域内单击
        /// </summary>
        /// <param name="x1">区域的左上X坐标</param>
        /// <param name="y1">区域的左上Y坐标</param>
        /// <param name="x2">区域的右下X坐标</param>
        /// <param name="y2">区域的右下Y坐标</param>
        /// <param name="first_color">颜色 格式为"RRGGBB-DRDGDB",</param>
        /// <param name="offset_color">偏移颜色 可以支持任意多个点</param>
        /// <param name="xx1">待点击区域的左上X坐标</param>
        /// <param name="yy1">待点击区域的左上Y坐标</param>
        /// <param name="xx2">待点击区域的右下X坐标</param>
        /// <param name="yy2">待点击区域的右下Y坐标</param>
        /// <param name="preDelay">移动前延时</param>
        /// <param name="postDelay">点击后延时</param>
        /// <param name="sim">相似度,取值范围0.1-1.0</param>
        /// <param name="isTrack">是否轨迹移动</param>
        /// <param name="log">输出日志，当找到时输出</param>
        /// <param name="clickDelay">移动后单击前延时，默认100-200范围内</param>
        /// <returns></returns>
        public FindResultEntity FindColorClickRange(int x1, int y1, int x2, int y2, string colorFirst, string colorOffset, int xx1, int yy1, int xx2, int yy2, int preDelay, int postDelay, double sim, bool isTrack, string log, int floatX, int floatY, int clickDelay = 200)
        {
            var result = FindColorExist(x1, y1, x2, y2, colorFirst, colorOffset, sim, log);
            if (result.Result)
            {
                MoveClick(_rand.Next(xx1, xx2), _rand.Next(yy1, yy2), preDelay, postDelay, isTrack, floatX, floatY, clickDelay);
            }
            return result;
        }

        /// <summary>
        /// 移动单击
        /// </summary>
        /// <param name="x1">X坐标</param>
        /// <param name="y1">Y坐标</param>
        /// <param name="preDelay">移动前延时</param>
        /// <param name="postDelay">点击后延时</param>
        /// <param name="isTrack">是否轨迹移动</param>
        /// <param name="isTrack">是否精确到点</param>
        /// <param name="floatX">点击点X轴浮动量</param>
        /// <param name="floatY">点击点Y轴浮动量</param>
        /// <param name="clickDelay">移动后单击前延时，默认100-200范围内</param>
        public void MoveClick(int x1, int y1, int preDelay, int postDelay, bool isTrack, int floatX = 0, int floatY = 0, int clickDelay = 200)
        {
            if (floatX > 0)
            {
                x1 += _rand.Next(floatX * 2) - floatX;

            }
            if (floatY > 0)
            {
                y1 += _rand.Next(floatY * 2) - floatY;
            }
            preDelay += _rand.Next(50) - 25;
            postDelay += _rand.Next(50) - 25;
            Thread.Sleep(preDelay);
            if (isTrack)
            {
                MoveTrack(x1, y1);
            }
            else
            {
                MoveTo(x1, y1);
            }
            Thread.Sleep(clickDelay / 2 + _rand.Next(clickDelay / 2));
            LeftClick();
            Thread.Sleep(postDelay);
        }
        #endregion
    }
}
